package com.choudou5.spider.util;

import cn.hutool.core.map.MapUtil;
import com.choudou5.solr.util.http.HttpUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.select.Elements;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 爬虫网页 工具类 (慎重改方法)
 *
 * @author choudou5
 * @create 2017-11-下午 6:01
 **/
public class SpiderHtmlUtil {

    /**
     * 包装 网页标签
     *
     * @param html
     * @param wrapTag
     * @return
     */
    public static String wrapTag(String html, String wrapTag) {
        return "<" + wrapTag + ">" + html + "</" + wrapTag + ">";
    }


    /**
     * 获取 属性值
     *
     * @param attrKey
     * @param ele
     * @return
     */
    public static String getAttrValue(String attrKey, Elements ele) {
        //检查是否为 function提取 eg: a@onclick#/category/{1}/{0}.html
        if (StringUtils.contains(attrKey, "#")) {
            String[] array = StringUtils.split(attrKey, "#", 2);
            String attrVal = ele.attr(array[0]);
            String tpl = array[1];//模板
            //组装模板参数
            if (array.length == 2) {
                //url字段模板则提取 url参数
                if (isUrlTplParamType(tpl)) {
                    Map<String, String> params = HttpUtils.getUrlParams(attrVal);
                    return replaceTplParam(tpl, params);
                } else {
                    List<String> paramNameList = getFunctionParams(attrVal);
                    List<Integer> paramIndexList = getTplParamIndexList(tpl);
                    return replaceTplParam(attrVal, tpl, paramNameList, paramIndexList);
                }
            } else {
                //获取 function 链接值
                return getFunctionLink(attrVal);
            }
        } else {
            String attrVal = ele.attr(attrKey);
            return getFunctionLink(attrVal);
        }
    }

    /**
     * 获取 模板 参数下标
     *
     * @param tpl
     * @return
     */
    public static List<Integer> getTplParamIndexList(String tpl) {
        List<Integer> indexList = new ArrayList<>(5);
        char[] chars = tpl.toCharArray();
        boolean append = false;
        for (char c : chars) {
            if (c == '{') {
                append = true;
                continue;
            } else if (c == '}') {
                append = false;
                continue;
            }
            if (append) {
                indexList.add(Integer.parseInt(String.valueOf(c)));
            }
        }
        return indexList;
    }


    /**
     * 是否为 url模板参数类型 判断是否含有{key}
     *
     * @param tpl
     * @return
     */
    public static boolean isUrlTplParamType(String tpl) {
        char[] chars = tpl.toCharArray();
        boolean append = false;
        for (char c : chars) {
            if (c == '{') {
                append = true;
                continue;
            }
            if (append) {
                return !isDigit(c);
            }
        }
        return false;
    }

    private static boolean isDigit(char c) {
        return (c >= 48 && c <= 59); //0-9
    }


    /**
     * 替换 模板参数
     *
     * @param originalParamVal 原始参数值
     * @param tpl
     * @param paramNameList
     * @param paramIndexList
     * @return
     */
    public static String replaceTplParam(String originalParamVal, String tpl, List<String> paramNameList, List<Integer> paramIndexList) {
        //处理 拼接值
        if (CollectionUtils.isEmpty(paramNameList) && CollectionUtils.isNotEmpty(paramIndexList)) {
            originalParamVal = checkSpecialUrl(originalParamVal);
            if (StringUtils.isNotBlank(originalParamVal) && originalParamVal.startsWith("http")) {
                return originalParamVal;
            } else {
                return StringUtils.replace(tpl, "{0}", originalParamVal);
            }
        }
        if (paramNameList.size() < paramIndexList.size()) {
            throw new IllegalArgumentException("jsoup模板参数个数与{}下标个数不一致.");
        }
        for (Integer paramIndex : paramIndexList) {
            tpl = StringUtils.replace(tpl, "{" + paramIndex + "}", paramNameList.get(paramIndex));
        }
        return tpl;
    }

    /**
     * 替换 模板参数
     *
     * @param tpl
     * @param params
     * @return
     */
    public static String replaceTplParam(String tpl, Map<String, String> params) {
        if (MapUtil.isNotEmpty(params)) {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                tpl = StringUtils.replace(tpl, "{" + entry.getKey() + "}", entry.getValue());
            }
        }
        return tpl;
    }


    /**
     * 检查 特殊url
     *
     * @param content
     * @return
     */
    private static String checkSpecialUrl(String content) {
        if (StringUtils.startsWith(content, "..")) {
            return StringUtils.substring(content, 2, content.length());
        }
        return content;
    }

    /**
     * 获取 函数参数
     *
     * @param fun
     * @return
     */
    public static List<String> getFunctionParams(String fun) {
        List<String> params = new ArrayList<>(5);
        char[] chars = fun.toCharArray();
        StringBuilder paramBuilder = new StringBuilder(36);
        boolean append = false;
        for (char c : chars) {
            if (c == ' ') {
                continue;
            } else if (c == '(') {
                append = true;
                continue;
            } else if (c == '\'' || c == '"') {
                append = true;
                continue;
            } else if (c == ',') {
                append = true;
                params.add(paramBuilder.toString());
                paramBuilder.delete(0, paramBuilder.length());//清除字段
                continue;
            } else if (c == ')') {
                append = false;
                break;
            }
            if (append) {
                paramBuilder.append(c);
            }
        }
        if (paramBuilder.length() > 0)
            params.add(paramBuilder.toString());
        return params;
    }

    /**
     * 获取 function 链接值
     *
     * @param funVal
     * @return
     */
    public static String getFunctionLink(String funVal) {
        String openMode = "window.open(";  //window.open ('page.html')
        int openIndex = StringUtils.indexOf(funVal, openMode);
        if (openIndex != -1) {
            return StringUtils.substring(funVal, openIndex + openMode.length() + 1, funVal.length() - 2);
        }
        String hrefMode = "href=";  //<a onclick="location.href='/w/bid/tenderAnnQuaInqueryAnn/15448/details.html'" title="会宁县平头川>白银</a>
        int hrefIndex = StringUtils.indexOf(funVal, hrefMode);
        if (hrefIndex != -1) {
            int excludeLen = 0;
            if (funVal.endsWith("'"))
                excludeLen = 1;
            return StringUtils.substring(funVal, hrefIndex + hrefMode.length() + excludeLen, funVal.length() - excludeLen);
        }
        return funVal;
    }

    /**
     * 检查 特殊网页内容
     * @param html
     * @return
     */
    public static String checkSpecialHtmlContent(String html) {
        if (StringUtils.startsWith(html, "'") && StringUtils.endsWith(html, "'")) {
            html = StringUtils.substring(html, 2, html.length() - 2);
        }
        if (StringUtils.startsWith(html, "<li>")) {
            html = wrapTag(html, "ul");
        }
        return html;
    }

}
